/*
 * @Author: your name
 * @Date: 2021-09-01 16:29:18
 * @LastEditTime: 2021-09-08 09:50:06
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \web-maps\src\util\mdfs\binary4\binary4Parser.ts
 */

import BinaryReader from "../BinaryReader";

export interface Info {
  mdfs: string;
  type: number;
  modelNames: string;
  elements: string;
  descriptions: string;
  level: number;
  year: number;
  month: number;
  day: number;
  hour: number;
  timezone: number;
  period: number;
  startLon: number;
  endLon: number;
  _xInterval: number;
  xSize: number;
  startLat: number;
  endLat: number;
  _yInterval: number;
  ySize: number;
  startValue: number;
  endValue: number;
  lineInterval: number;
}

export interface GridData {
  position: [number, number];
  value: number;
}

export interface GridDataList {
  data: Array<GridData>;
  minValue: number;
  maxValue: number;
}

export default class Binary4Parser extends BinaryReader {
  private info!: Info;

  constructor(buffer: ArrayBuffer) {
    super(new DataView(buffer));
  }

  private headerInfo() {
    let info = {} as Info;

    info.mdfs = this.replaceEnd(this.ReadChars(4));
    info.type = this.ReadInt16();
    info.modelNames = this.replaceEnd(this.ReadChars(20));
    info.elements = this.replaceEnd(this.ReadChars(50));
    info.descriptions = this.replaceEnd(this.ReadChars(30));

    info.level = this.ReadFloat32();
    info.year = this.ReadInt32();
    info.month = this.ReadInt32();
    info.day = this.ReadInt32();
    info.hour = this.ReadInt32();
    info.timezone = this.ReadInt32();
    info.period = this.ReadInt32();

    info.startLon = this.ReadFloat32();
    info.endLon = this.ReadFloat32();
    info._xInterval = Number(this.ReadFloat32().toFixed(3));
    info.xSize = this.ReadInt32();
    info.startLat = this.ReadFloat32();
    info.endLat = this.ReadFloat32();
    info._yInterval = Number(this.ReadFloat32().toFixed(3));
    info.ySize = this.ReadInt32();

    info.startValue = Number.parseFloat(this.ReadFloat32().toFixed(2));
    info.endValue = Number.parseFloat(this.ReadFloat32().toFixed(2));
    info.lineInterval = this.ReadFloat32();

    this.info = info;
  }

  private ParseGridData() {
    let extent = this.ReadBytes(100);

    const count = extent[2] === 0 ? 1 : extent[2];

    const {
      startLon,
      startLat,
      xSize,
      ySize,
      _yInterval,
      _xInterval,
    } = this.info;

    const gridDataList: Array<GridDataList> = [];

    let [long, lat] = [Number(startLon), Number(startLat)];

    for (let m = 0; m < count; m++) {
      let maxValue = -9999,
        minValue = 9999;

      if (m > 0) extent = this.ReadBytes(278);

      const gridSize = xSize * ySize * 4;
      const data: Array<GridData> = [];

      const primitiveData: Array<number> = [];

      for (let i = 0; i < gridSize; i += 4) {
        primitiveData.push(this.ReadFloat32());
      }

      for (let i = 0; i < ySize; i++) {
        const _lat = i * _yInterval + lat;
        for (let j = 0; j < xSize; j++) {
          const gridIndex = i * xSize + j;
          const _long = j * _xInterval + long;

          const value = Number(primitiveData[gridIndex]);
          data.push({
            position: [_long, _lat],
            // value: Number.parseFloat(
            //     Number(primitiveData[gridIndex]).toFixed(1)),
            value:
              Infinity === value || -Infinity === value || Number.isNaN(value)
                ? 9999
                : value,
          });

          if (value != 9999) {
            if (value > maxValue) maxValue = value;
            else if (value < minValue) minValue = value;
          }
        }
      }

      gridDataList.push({
        data,
        minValue,
        maxValue,
      });
    }

    return gridDataList;
  }

  Parse() {
    this.headerInfo();

    //mdfs://EC/APCP_03/2022061708.000  - mdfs://EC/APCP_03/2022061708.024 间隔 03

    return {
      info: this.info,
      gridDatas: this.ParseGridData(),
    };
  }
}
